/********************************************************/
/*	Copyright (C) 2012 Gong Li Bin			*/
/*	Project:	MapReduce			*/
/*	Author:		gong_libin			*/
/*	Date:		2013_05_08			*/
/*	File:		MrReport.cpp			*/
/********************************************************/

#include "MrReport.h"

bool g_bDebug = false;
MRREPORTCONF_S g_stConf;

int main(int argc, char* argv[])
{
	int iIndex = 0;
	int iReturn = 0;
	bool bFork = false;
	UCHAR ucType = MR_PL_NLL;
	char szConf[MR_BUFFER] = "MrReport.conf";

	struct option stOptions[] = {
		{"conf", 1, 0, 'c'},
		{"avg", 0, 0, 'a'},
		{"cpu", 0, 0, 'u'},
		{"dsk", 0, 0, 's'},
		{"ios", 0, 0, 'i'},
		{"mem", 0, 0, 'm'},
		{"fork", 0, 0, 'f'},
		{"debug", 0, 0, 'd'},
		{"help", 0, 0, 'h'},
		{"version", 0, 0, 'v'},
		{0, 0, 0, 0},
	};

	while (true) {
		iReturn = getopt_long(argc, argv, "c:ausimfdhv", stOptions, &iIndex);
		if (iReturn < 0) {
			break;
		}
		switch (iReturn) {
			case 'c':
				strncpy(szConf, optarg, MR_BUFFER);
				break;
			case 'a':
				ucType |= MR_PL_AVG;
				break;
			case 'u':
				ucType |= MR_PL_CPU;
				break;
			case 's':
				ucType |= MR_PL_DSK;
				break;
			case 'i':
				ucType |= MR_PL_IOS;
				break;
			case 'm':
				ucType |= MR_PL_MMR;
				break;
			case 'f':
				bFork = true;
				break;
			case 'd':
				g_bDebug = true;
				break;
			case 'h':
				MrReportHelp(argv[0]);
				return MR_SUCCESS;
			case 'v':
				MR_PRINT("Copyright (C) 2012 Gong Li Bin	\n");
				MR_PRINT("%s Build on %s %s.\n", MR_RT_VERSION, __DATE__, __TIME__);
				return MR_SUCCESS;
			default:
				return MR_SUCCESS;
		}
	}

	if (MR_PL_NLL == ucType) {
		MrReportHelp(argv[0]);
		return MR_SUCCESS;
	}

	signal(SIGSEGV, MrReportQuit);
	signal(SIGTERM, MrReportQuit);

	if (true == g_bDebug) {
		MR_DEBUG("Initialize config from %s\n", szConf);
	}
	if (MR_SUCCESS == MrReportConfig(szConf)) {
		if (true == g_bDebug) {
			MR_DEBUG("HostID: %s\n", g_stConf.m_szHostID);
			MR_DEBUG("Timeslice: %s\n", g_stConf.m_szTimeslice);
			MR_DEBUG("MultiAddr: %s\n", g_stConf.m_szMultiAddr);
			MR_DEBUG("MultiPort: %s\n", g_stConf.m_szMultiPort);
		}
	}
	else {
		MR_ERROR("Failed to config\n");
		return MR_FAILURE;
	}

	if (true != g_bDebug) {
		MrFork();
	}

	if (true != g_bDebug) {
		while (true) {
			usleep(atoi(g_stConf.m_szTimeslice));
			if (true == bFork) {
				signal(SIGCHLD, SIG_IGN);
				MrReportFork(ucType);
			}
			else {
				MrReportCore(ucType);
			}
		}
	}
	else {
		if (true == bFork) {
			MrReportFork(ucType);
		}
		else {
			MrReportCore(ucType);
		}
	}

	return MR_SUCCESS;
}

void MrReportHelp(char* pszProc)
{
	MR_PRINT("Usage: %s [options]\n", pszProc);
	MR_PRINT("Valid options are:\n");
	MR_PRINT("[*] -c or --conf:       set configure.\n");
	MR_PRINT("[*] -a or --avg:        set arv getting.\n");
	MR_PRINT("[*] -u or --cpu:        set cpu getting.\n");
	MR_PRINT("[*] -s or --dsk:        set dsk getting.\n");
	MR_PRINT("[*] -i or --ios:        set ios getting.\n");
	MR_PRINT("[*] -m or --mem:        set mem getting.\n");
	MR_PRINT("[0] -f or --fork:       set fork mode.\n");
	MR_PRINT("[0] -d or --debug:      set debug mode.\n");
	MR_PRINT("[0] -h or --help:       show help.\n");
	MR_PRINT("[0] -v or --version:    show version.\n");
	MR_PRINT("Copyright (C) 2012 Gong Li Bin	\n");
	MR_PRINT("%s Build on %s %s.\n", MR_RT_VERSION, __DATE__, __TIME__);

	return;
}

void MrReportQuit(int iSignal)
{
	if (true == g_bDebug) {
		MR_DEBUG("MrReport is stopped by signal[%d]\n", iSignal);
	}

	exit(MR_FAILURE);
}

int MrReportConfig(char* pszConf)
{
	CMrDb CDb;
	MRCONFIG_S stConf;
	MRPROKV_S* pstKv = NULL;
	int iReturn = MR_SUCCESS;
	char szSql[MR_PACKET] = { 0 };

	memset(&stConf, '\0', sizeof(MRCONFIG_S));
	if (MR_SUCCESS == MrConfig(pszConf, &stConf)) {
		if (NULL != (pstKv = MrProKvMalloc(MR_BUFFER, MR_PACKET))) {
			if (MR_SUCCESS == CDb.MrDbConnect(stConf.m_szHost, stConf.m_szPort)) {
				sprintf(szSql, MR_RT_CONFIG, stConf.m_szDbase, stConf.m_szTable, stConf.m_szID);
				if (CDb.MrDbSend(MR_DEF_SELT, szSql) > 0) {
					if (MR_SUCCESS == CDb.MrDbRecv(pstKv)) {
						memcpy(g_stConf.m_szHostID, (pstKv + 0)->m_puszValue, (pstKv + 0)->m_iLength);
						memcpy(g_stConf.m_szTimeslice, (pstKv + 1)->m_puszValue, (pstKv + 1)->m_iLength);
						memcpy(g_stConf.m_szMultiAddr, (pstKv + 2)->m_puszValue, (pstKv + 2)->m_iLength);
						memcpy(g_stConf.m_szMultiPort, (pstKv + 3)->m_puszValue, (pstKv + 3)->m_iLength);
					}
					else {
						MR_ERROR("Failed to MrDbRecv\n");
						iReturn = MR_FAILURE;
					}
				}
				else {
					MR_ERROR("Failed to MrDbSend\n");
					iReturn = MR_FAILURE;
				}
				CDb.MrDbClose();
			}
			else {
				MR_ERROR("Failed to MrDbConnect\n");
				iReturn = MR_FAILURE;
			}
			MrProKvFree(&pstKv, MR_BUFFER);
		}
		else {
			MR_ERROR("Failed to MrProKvMalloc\n");
			iReturn = MR_FAILURE;
		}
	}
	else {
		MR_ERROR("Failed to MrConf\n");
		iReturn = MR_FAILURE;
	}

	return iReturn;
}

void MrReportFork(UCHAR ucType)
{
	switch (fork()) {
		case MR_SUCCESS:
			MrReportCore(ucType);
			exit(MR_SUCCESS);
			break;
		case MR_FAILURE:
			break;
		default:
			break;
	}

	return;
}

void MrReportCore(UCHAR ucType)
{
	CMrPro CPro;
	CMrAvg CAvg;
	CMrCpu CCpu;
	CMrDsk CDsk;
	CMrIos CIos;
	CMrMem CMem;
	CMrPipe CPipe;
	CMrTime CTime;
	MRPROKV_S stKv;
	CMrMulti CMulti;
	int iCount = 0;
	int iLength = 0;
	CMrCmd* pCCmd = NULL;
	UCHAR* puszPacket = NULL;
	USHORT usTotal = MR_PRO_1;
	UCHAR ucResult = MR_DEF_SUCC;
	MRPOLLCMD_S stCmd[] = {{MR_PL_AVG, (void*)MR_AVG_CMD}, {MR_PL_CPU, (void*)MR_CPU_CMD}, {MR_PL_DSK, (void*)MR_DSK_CMD}, {MR_PL_IOS, (void*)MR_IOS_CMD}, {MR_PL_MMR, (void*)MR_MMR_CMD}};

	if (true == g_bDebug) {
		CTime.MrTimeOn();
		MR_DEBUG("MrReportCore start\n");
	}

	if (NULL != (puszPacket = (UCHAR*)MrMalloc(MR_PIPE))) {
		stKv.m_ucKey = MR_PL_HOST;
		stKv.m_iLength = strlen(g_stConf.m_szHostID);
		stKv.m_puszValue = (UCHAR*)g_stConf.m_szHostID;
		iLength = MrProKvOutput(&stKv, usTotal, puszPacket + MR_PRO_HEAD, MR_PIPE);

		if (MR_SUCCESS == CPipe.MrPipeResultMalloc(MR_PIPE)) {
			while (iCount < MR_PL_TGT) {
				switch (stCmd[iCount].m_ucType & ucType) {
					case MR_PL_AVG:
						pCCmd = &CAvg;
						break;
					case MR_PL_CPU:
						pCCmd = &CCpu;
						break;
					case MR_PL_DSK:
						pCCmd = &CDsk;
						break;
					case MR_PL_IOS:
						pCCmd = &CIos;
						break;
					case MR_PL_MMR:
						pCCmd = &CMem;
						break;
					default:
						pCCmd = NULL;
						break;
				}

				if (NULL != pCCmd) {
					if (true == g_bDebug) {
						MR_PRINT("Command: %s\n", (char*)stCmd[iCount].m_pRemark);
					}
					if (MR_SUCCESS == CPipe.MrPipeOpen((char*)stCmd[iCount].m_pRemark, (char*)"r")) {
						if (CPipe.MrPipeRead(MR_PIPE) > 0) {
							if (true == g_bDebug) {
								MR_PRINT("%s\n", CPipe.MrPipeResultGet());
							}
							pCCmd->MrCmdInfo(CPipe.MrPipeResultGet());
							iLength += pCCmd->MrCmdResultOutput(puszPacket + MR_PRO_HEAD + iLength, &usTotal);
						}
						CPipe.MrPipeClose();
					}
				}

				CPipe.MrPipeResultReset(MR_PIPE);
				iCount += 1;
			}
			CPipe.MrPipeResultFree();
		}
		else {
			ucResult = MR_DEF_UNKN;
		}

		if (usTotal > MR_PRO_1) {
			CPro.MrProPutBody(NULL);
			CPro.MrProPutAttr(ucType);
			CPro.MrProPutReal(MR_PRO_0);
			CPro.MrProPutTotal(usTotal);
			CPro.MrProPutLength(iLength);
			CPro.MrProPutResult(ucResult);
			CPro.MrProPutExpand(MR_PRO_0);
			CPro.MrProPutVerb(MR_DEF_INST);
			CPro.MrProPutType(MR_DEF_POLL);
			CPro.MrProPutFlag(MR_PRO_FLAG);
			CPro.MrProPutVersion(MR_PRO_1);
			CPro.MrProPutResponse(MR_PRO_N);
			CPro.MrProPutProtocol(MR_PRO_CTRL);
			CPro.MrProCreate(puszPacket, MR_PIPE);
			if (MR_SUCCESS == CMulti.MrNetInitSend(g_stConf.m_szMultiAddr, g_stConf.m_szMultiPort)) {
				if (true == g_bDebug) {
					MR_DEBUG("Multicast packet, Length: %d, Total: %d\n", MR_PRO_HEAD + iLength, usTotal);
				}
				CMulti.MrNetSend(puszPacket, MR_PRO_HEAD + iLength);
				CMulti.MrNetClose();
			}
		}

		MrFree((void**)&puszPacket);
	}

	if (true == g_bDebug) {
		MR_DEBUG("MrReportCore end use ");
		CTime.MrTimeOff();
		CTime.MrTimeDisplay();
	}

	return;
}
